

<script setup>
    import { reactive, ref, watch } from 'vue';
    import {
        getTablePageSize,
        getAllTableNameList,
        getAllTableColumnNameList,
        getTableColumnKeyUsage,
        getTableColumnIsNullable,
        getTableColumnDefaultValue,
        getTableColumnDataType,
        formatDate,
        getTablePage,
        getTableTotalCount,
        searchTableByColumnValue,
        dbInsert,
        dbUpdateByID,
        dbDeleteByID
    } from "/request.js";


    // 通用数据
    const initLoading = ref(true);
    const pageSize = ref(0);                // 每页大小
    const tableNameList = reactive([]);     // 使用 索引
    const columnNameList = reactive({});    // 使用 tableName
    const columnsList = reactive({});       // table name 对应 其相关 columns 数据


    // 当前 tab 表名
    const currentTableName = ref("");


    // 数据读取相关
    const tabActiveKey = ref(0);
    const tablePageIndex = ref(1);
    const tableTotalCount = ref(0);
    const tableDataSource = reactive([]);
    const tableSearched = ref(false);

    const tablePaginationProps = reactive({
        current: tablePageIndex,
        pageSize: pageSize,
        total: tableTotalCount,
        onChange: (page, _pageSize) => {
            tablePageIndex.value = page;
        }
    });


    // 添加数据相关
    const dialogInsertOpen = ref(false);


    // 数据编辑相关
    const recordIndex = ref(0);
    const dialogUpdateOpen = ref(false);
    const dialogConfirmLoading = ref(false);
    var dialogFormData = reactive({});


    // 外键值选择相关
    const selectForeignKeyValueState = ref(false);
    const selectForeignKeyTableName = ref("");              // 外键关联的表的名字
    const selectForeignKeyColumnName = ref("");             // 外键关联的表的列的列名
    const selectForeignKeyTableTotalCount = ref(0);         // 外键选择表格的 数据总数
    const selectForeignKeyTablePageIndex = ref(1);          // 外键选择表格的 page 索引
    const selectForeignKeyValueTableDataSource = ref([]);   // 外键值选择表格 数据源
    const selectForeignKeyValueTableSearched = ref(false);  // 外键值选择表格 搜索状态


    const selectForeignKeyPaginationProps = reactive({
        current: selectForeignKeyTablePageIndex,
        pageSize: pageSize,
        total: selectForeignKeyTableTotalCount,
        onChange: (page, _pageSize) => {
            selectForeignKeyTablePageIndex.value = page;
        }
    });


    // 获取 column key usage
    // 一些为空值
    var columnKeyUsage = reactive({});
    async function updateColumnKeyUsage()
    {
        columnKeyUsage = reactive({});
        for (var name of columnNameList[currentTableName.value])
        {
            await getTableColumnKeyUsage(currentTableName.value, name)
            .then(function(usage) {
                columnKeyUsage[name] = usage;
            });
        }
    }


    // 列能否为空值，切 tab 时调用
    var columnIsNullable = reactive({});
    async function updateColumnIsNullable()
    {
        columnIsNullable = reactive({});
        for (var name of columnNameList[currentTableName.value])
        {
            await getTableColumnIsNullable(currentTableName.value, name)
            .then(function(is) {
                columnIsNullable[name] = is;
            });
        }
    }
    


    // 数据读取相关
    getTablePageSize()
    .then(function(size) {
        pageSize.value = size;
    });

    async function init()
    {
        await getAllTableNameList()
        .then(async function(list) {
            for (var name of list)
            {
                tableNameList.push(name);
            }

            for (var i = 0; i < tableNameList.length; i++)
            {
                columnNameList[tableNameList[i]] = [];
                columnsList[tableNameList[i]] = [];
                tableDataSource[i] = [];
                await getAllTableColumnNameList(tableNameList[i])
                .then(function(list) {
                    for (var name of list)
                    {
                        columnNameList[tableNameList[i]].push(name);
                        columnsList[tableNameList[i]].push({
                            align: "center",
                            title: name,
                            dataIndex: name,
                            key: name,
                            ellipsis: true,     // 内容超过最大宽度是否自带省略
                        });
                        
                    }
                    columnsList[tableNameList[i]].push({
                        align: "center",
                        title: "操作",
                        dataIndex: "operation",
                        key: "operation",
                    });
                });
            }

        });
        initLoading.value = false;
    }
    init();
    


    // 通过 返回的 数据列表 获取 数据源
    async function getDataSourceByReturnList(tableName, list)
    {
        const dataSource = [];

        for (var i = 0; i < list.length; i++)
        {
            var data = {
                key: ( i + 1 ).toString()
            };
            for (const [key, value] of Object.entries(list[i]))
            {
                var v = value;
                await getTableColumnDataType(tableName, key)
                .then(function(type) {
                    if (type === "datetime")
                        v = formatDate(new Date(value));
                });
                data[key] = v;
            }

            dataSource.push(data);
        }
        return dataSource;
    }




    // 搜索相关
    const searchLoading = ref(false);
    const searchSelectColumnName = ref("id");
    const searchValue = ref("");
    // 获取 search 数据源
    async function getSearchDataSource(tableName)
    {
        if (!searchSelectColumnName.value || !searchValue.value)
            return;

        var dataSource = [];
        searchLoading.value = true;
        await searchTableByColumnValue(tableName, searchSelectColumnName.value, searchValue.value)
        .then(async function(list) {
            await getDataSourceByReturnList(tableName, list)
            .then(function(ds) {
                dataSource = ds;
            });
            searchLoading.value = false;
        });
        return dataSource;
    }



    // 获取 page 数据源
    async function getPageDataSource(tableName, pageIndex)
    {
        var dataSource = [];
        await getTablePage(tableName, pageIndex)
        .then(async function(list) {
            await getDataSourceByReturnList(tableName, list)
            .then(function(ds) {
                dataSource = ds;
            })
        });
        return dataSource;
    }


    // 更新 显示页 数据
    async function updatePage()
    {
        if (tableSearched.value)
        {
            return;
        }

        await getTableTotalCount(currentTableName.value)
        .then(function(count) {
            tableTotalCount.value = count;
        });
        getPageDataSource(currentTableName.value, tablePageIndex.value)
        .then(function(ds) {
            tableDataSource[tabActiveKey.value] = ds;
        });
    }


    function clickTableSearch()
    {
        // tableName = currentTableName.value
        tableSearched.value = true;
        getSearchDataSource(currentTableName.value)
        .then(function(ds) {
            tableTotalCount.value = ds.length;
            tableDataSource[currentTableName.value] = ds;
        });
    }


    // 修改当前表名
    // 消除搜索状态
    // 更改当前 table 页
    // 更新 columnKeyUsage 数据
    // 更新 columnIsNullable 数据
    // 更新 当前页（第一页） 数据
    watch(tabActiveKey, async function(_newV, _oldV) {
        currentTableName.value = tableNameList[tabActiveKey.value];
        tableSearched.value = false;
        tablePageIndex.value = 1; // 页数改为 1
        await updateColumnKeyUsage();
        await updateColumnIsNullable();
        updatePage();
    });
    watch(tablePageIndex, async function(_newV, _oldV) {
        if (!tableSearched.value)
        {
            updatePage();
        }
    });

    



    // 数据添加相关
    async function showInsertDialog()
    {
        dialogFormData = reactive({});
        dialogInsertOpen.value = true;
        for (var name of columnNameList[currentTableName.value])
        {
            await getTableColumnDefaultValue(currentTableName.value, name)
            .then(function(value) {
                if (!value)
                    return;
                if (value === "NULL")
                    return;
                if (!value.includes("()"))
                    dialogFormData[name] = value;
            });
        }
    }


    function submitInsert()
    {
        for (const [key, value] of Object.entries(columnIsNullable))
        {
            if (!dialogFormData[key] && !value && !(key === 'id'))
            {
                alert(key + "不能为空值");
                return;
            }
        }

        dialogConfirmLoading.value = true;
        setTimeout(function() {
            if (dialogConfirmLoading.value)
            {
                dialogConfirmLoading.value = false;
                alert("添加失败，可能是数据有误");
                dialogInsertOpen.value = false;
            }
        }, 2000);
        dbInsert(currentTableName.value, dialogFormData)
        .then(function(type) {
            dialogConfirmLoading.value = false;
            if (type === "Success")
            {
                dialogInsertOpen.value = false;
                updatePage();
            }
        });
    }



    // 数据编辑相关
    function showUpdateDialog(rIndex) {
        recordIndex.value = rIndex;
        dialogFormData = reactive({});
        for (var name of columnNameList[currentTableName.value])
        {
            dialogFormData[name] = tableDataSource[tabActiveKey.value][recordIndex.value][name];
        }

        dialogUpdateOpen.value = true;
    };



    function submitUpdate()
    {
        for (const [key, value] of Object.entries(columnIsNullable))
        {
            if (!dialogFormData[key] && !value && !(key === 'id'))
            {
                alert(key + "不能为空值");
                return;
            }
        }

        dialogConfirmLoading.value = true;
        setTimeout(function() {
            if (dialogConfirmLoading.value)
            {
                dialogConfirmLoading.value = false;
                alert("修改失败，可能是数据有误");
                dialogInsertOpen.value = false;
            }
        }, 2000);
        const id = tableDataSource[tabActiveKey.value][recordIndex.value]['id'];
        delete dialogFormData.id;
        dbUpdateByID(currentTableName.value, id, dialogFormData)
        .then(function(type) {
            dialogConfirmLoading.value = false;
            if (type === "Success")
            {
                dialogUpdateOpen.value = false;
                updatePage();
            }
        });
    }


    // 选择外键值相关
    watch(dialogInsertOpen, function(newV, _oldV) {
        if (!newV)
            selectForeignKeyValueState.value = false;
    })
    watch(dialogUpdateOpen, function(newV, _oldV) {
        if (!newV)
            selectForeignKeyValueState.value = false;
    })

    function columnIsNotNull(columnName) {
        if (!columnIsNullable[columnName])
            return true;
        return false;
    }
    function columnIsForeignKey(columnName) {
        if (!columnKeyUsage[columnName])
            return false;
        if (columnKeyUsage[columnName].CONSTRAINT_NAME === "PRIMARY")
            return false;
        if (!columnKeyUsage[columnName].REFERENCED_TABLE_NAME)
            return false;
        if (!columnKeyUsage[columnName].REFERENCED_COLUMN_NAME)
            return false;
        if (columnKeyUsage[columnName].REFERENCED_TABLE_NAME === 'NULL')
            return false;
        if (columnKeyUsage[columnName].REFERENCED_COLUMN_NAME === 'NULL')
            return false;
        return true;
    }

    var selectLastSelectColumnName = "";
    async function showSelectForeignKeyValueTable(columnName)
    {
        selectForeignKeyValueTableSearched.value = false;
        if (selectLastSelectColumnName === columnName)
        {
            selectLastSelectColumnName = "";
            selectForeignKeyValueState.value = false;
            return;
        }
        else
        {
            selectLastSelectColumnName = columnName;
        }
        if (!selectForeignKeyValueState.value)
        selectLastSelectColumnName = columnName;


        if (selectForeignKeyValueState.value)
            selectForeignKeyValueState.value = false;
        selectForeignKeyTableName.value = columnKeyUsage[columnName].REFERENCED_TABLE_NAME;
        selectForeignKeyColumnName.value = columnKeyUsage[columnName].REFERENCED_COLUMN_NAME;

        await getTableTotalCount(selectForeignKeyTableName.value)
        .then(function(count) {
            selectForeignKeyTableTotalCount.value = count;
        }); 
        await getPageDataSource(selectForeignKeyTableName.value, 1)
        .then(function(ds) {
            selectForeignKeyValueTableDataSource.value = ds;
        });

        selectForeignKeyValueState.value = true;
    }
    watch(selectForeignKeyValueState, function(_newV, _oldV) {
        if (!selectForeignKeyValueState.value)
        {
            selectForeignKeyTableTotalCount.value = 0;
            selectForeignKeyTablePageIndex.value = 1;
            selectForeignKeyValueTableDataSource.value = [];
        }
    });
    watch(selectForeignKeyTablePageIndex, function(newV, _oldV) {
        if (selectForeignKeyValueState.value)
        {
            getPageDataSource(selectForeignKeyTableName.value, newV)
            .then(function(ds) {
                selectForeignKeyValueTableDataSource.value = ds;
            });
        }
    });

    // click 外键值选择表格 选择按钮
    function clickSelectForeignKeyValue(rIndex)
    {
        dialogFormData[selectLastSelectColumnName] = selectForeignKeyValueTableDataSource.value[rIndex][selectForeignKeyColumnName.value];
        selectForeignKeyValueState.value = false;
    }

    function clickSelectForeignKeyValueTableSearch()
    {
        // tableName = selectForeignKeyTableName.value
        selectForeignKeyValueTableSearched.value = true;
        getSearchDataSource(selectForeignKeyTableName.value)
        .then(function(ds) {
            selectForeignKeyTableTotalCount.value = ds.length;
            selectForeignKeyValueTableDataSource.value = ds;
        });
    }




    function submitDelete(rIndex)
    {
        recordIndex.value = rIndex;
        const id = tableDataSource[tabActiveKey.value][recordIndex.value]['id'];
        dbDeleteByID(currentTableName.value, id)
        .then(function(type) {
            if (type === "Success")
            {
                updatePage();
            }
        });
    }
</script>


<template>
    <a-tabs
        v-if="!initLoading"
        v-model:activeKey="tabActiveKey"
        :style="{ height: '200px' }"
    >
        <a-tab-pane v-for="(tableName, tableIndex) of tableNameList" :key="tableIndex" :tab="tableName">

            <a-table
                :scroll="{ x: 2000, y: 500 }"
                :dataSource="tableDataSource[tableIndex]"
                :columns="columnsList[tableName]"
                :pagination="tablePaginationProps"
            >
                <template #title>
                    <a-row style="justify-content: space-between;">
                        <div>
                            <a-button type="primary" @click="showInsertDialog">新增</a-button>
                        </div>
                        
                        <div>
                            <a-input-search
                                placeholder="请输入要搜索的值"
                                enter-button
                                v-model:value="searchValue"
                                :loading="searchLoading"
                                @search="clickTableSearch()"
                            >
                                <template #addonBefore>
                                    <a-select v-model:value="searchSelectColumnName" style="width: auto">
                                        <a-select-option v-for="name of columnNameList[tableName]" :value="name">{{ name }}</a-select-option>
                                    </a-select>
                                </template>
                            </a-input-search>
                        </div>
                        
                    </a-row>
                    
                </template>


                <!-- index 为 record 索引 -->
                <template #bodyCell="{text, record, index, column}">
                    <a-space v-if="column.key === 'operation'">
                        <a-button type="primary" @click="showUpdateDialog(index)">编辑</a-button>
                        <a-button danger @click="submitDelete(index)">删除</a-button>
                    </a-space>
                </template>
            </a-table>

        </a-tab-pane>
    </a-tabs>


    <div class="loading">
        <a-spin size="large" :spinning="initLoading" />
    </div>


    <!-- 添加数据dialog -->
    <a-modal
        class="dialog"
        v-if="dialogInsertOpen"
        v-model:open="dialogInsertOpen"
        title="添加数据"
        :confirm-loading="dialogConfirmLoading"
        @ok="submitInsert"
    >


        <a-form>
            <a-form-item
                v-for="name of columnNameList[currentTableName]"
                :label="name"
                :name="name"
            >
                <a-input
                    v-model:value="dialogFormData[name]"
                    :disabled="name === 'id' || columnIsForeignKey(name)"
                >
                    <template #addonAfter v-if="!(name === 'id') && (columnIsNotNull(name) || columnIsForeignKey(name))">
                        <a-tag color="error" v-if="!columnIsForeignKey(name)">NotNull</a-tag>
                        <a-button
                            v-if="columnIsForeignKey(name)"
                            type="text"
                            @click="showSelectForeignKeyValueTable(name)"
                        >
                            选择关联值
                        </a-button>
                    </template>
                </a-input>
            </a-form-item>
        </a-form>


        <!-- 外键值选择表格 -->
        <a-table
            v-if="selectForeignKeyValueState"
            :scroll="{x: 2000, y: 500}"
            :columns="columnsList[selectForeignKeyTableName]"
            :dataSource="selectForeignKeyValueTableDataSource"
            :pagination="selectForeignKeyPaginationProps"
        >
            <template #title>
                <a-row style="justify-content: space-between;">
                    <div>
                    </div>
                    <div>
                        <a-input-search
                            placeholder="请输入要搜索的值"
                            enter-button
                            v-model:value="searchValue"
                            :loading="searchLoading"
                            @search="clickSelectForeignKeyValueTableSearch()"
                        >
                            <template #addonBefore>
                                <a-select v-model:value="searchSelectColumnName" style="width: auto">
                                    <a-select-option v-for="columnName of columnNameList[selectForeignKeyTableName]" :value="columnName">{{ columnName }}</a-select-option>
                                </a-select>
                            </template>
                        </a-input-search>
                    </div>
                    
                </a-row>
                
            </template>


            <template #bodyCell="{text, record, index, column}" >
                <template v-if="column.key === 'operation'">
                    <a-button type="primary" @click="clickSelectForeignKeyValue(index)">选择</a-button>
                </template>
            </template>

        </a-table>
        
    </a-modal>


    <!-- 编辑dialog -->
    <a-modal
        class="dialog"
        v-if="dialogUpdateOpen"
        v-model:open="dialogUpdateOpen"
        title="编辑"
        :confirm-loading="dialogConfirmLoading"
        @ok="submitUpdate"
    >
        <a-form>
            <a-form-item
                v-for="name of columnNameList[currentTableName]"
                :label="name"
                :name="name"
            >
                <a-input
                    v-model:value="dialogFormData[name]"
                    :disabled="name === 'id' || columnIsForeignKey(name)"
                >
                    <template #addonAfter v-if="!(name === 'id') && (columnIsNotNull(name) || columnIsForeignKey(name))">
                        <a-tag color="error" v-if="!columnIsForeignKey(name)">NotNull</a-tag>
                        <a-button
                            v-if="columnIsForeignKey(name)"
                            type="text"
                            @click="showSelectForeignKeyValueTable(name)"
                        >
                            选择关联值
                        </a-button>
                    </template>
                </a-input>
            </a-form-item>
        </a-form>


        <!-- 外键值选择表格 -->
        <a-table
            v-if="selectForeignKeyValueState"
            :scroll="{x: 2000, y: 500}"
            :columns="columnsList[selectForeignKeyTableName]"
            :dataSource="selectForeignKeyValueTableDataSource"
            :pagination="selectForeignKeyPaginationProps"
        >
            <template #title>
                <a-row style="justify-content: space-between;">
                    <div>
                    </div>
                    <div>
                        <a-input-search
                            placeholder="请输入要搜索的值"
                            enter-button
                            v-model:value="searchValue"
                            :loading="searchLoading"
                            @search="clickSelectForeignKeyValueTableSearch()"
                        >
                            <template #addonBefore>
                                <a-select v-model:value="searchSelectColumnName" style="width: auto">
                                    <a-select-option v-for="columnName of columnNameList[selectForeignKeyTableName]" :value="columnName">{{ columnName }}</a-select-option>
                                </a-select>
                            </template>
                        </a-input-search>
                    </div>
                    
                </a-row>
                
            </template>


            <template #bodyCell="{text, record, index, column}" >
                <template v-if="column.key === 'operation'">
                    <a-button type="primary" @click="clickSelectForeignKeyValue(index)">选择</a-button>
                </template>
            </template>

        </a-table>
    </a-modal>

    
</template>

<style>
    .loading {
        position: fixed;
        left: 50%;
        top: 50%;
    }

</style>


